/*================================================================
*   Copyright (C) 2018 Sangfor Ltd. All rights reserved.
*   
*   文件名称：main.c
*   创 建 者：yysshh
*   创建日期：2018年12月24日
*   描    述：
*
================================================================*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<termios.h>
#include<fcntl.h>
#include<time.h>

#define WIDTH 29
#define HEIGHT 14
#define WIDTH_2 12
#define MAX_LENGTH 50

enum MOVE_DIR {UP = -1, DOWN = 1 , LEFT = 2, RIGHT = 4};
enum MOVE_DIR cur_dir = RIGHT;
int game_over = 0;
int snake_length = 3;
int delay = 500000;
int score = 0;

struct snake_node
{
	int x;
	int y;
	enum MOVE_DIR dir;
}snake[MAX_LENGTH];

struct snake_node food;

void make_food()
{
	int i, food_f = 1;
	while(food_f)
	{
		food.x = rand()%(HEIGHT - 2) + 1;
		food.y = rand()%(WIDTH - 2) + 1;
		for(i = 0 ; i < snake_length ; i++)
		{
			if(snake[i].x == food.x && snake[i].y == food.y)
				break;
		}
		if(i == snake_length) food_f = 0;
	}
}

void speed()
{
	switch(score)
	{
		case 40:delay = 500000;break;
		case 60:delay = 400000;break;
		case 80:delay = 300000;break;
		case 100:delay = 200000;break;
		default:break;
	}
}

void init()
{
	int i;
	for(i = 0 ; i < snake_length ; i++)
	{
		snake[i].x= 3;
		snake[i].y= 3 + i;
		snake[i].dir= cur_dir;
	}
	srand(time(0));
	make_food();
}

void display()
{
	char ground[HEIGHT][WIDTH + 2 + WIDTH_2] = {
				 "+ + + + + + + + + + + + + + + + + + + + +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+                           +           +\n",
				 "+ + + + + + + + + + + + + + + + + + + + +\n"
													};
	int i,score_l;
	system("clear");
	for(i = 0 ; i < snake_length ; i++)
	{
		ground[ snake[i].x ][ snake[i].y ] = '*';
	}
	
	ground[ food.x ][ food.y ] = 'O';

	if(score == 0)
		ground[1][WIDTH + 6] = '0';
	else
		for(score_l = score, i = 6 ; score_l > 0 ; score_l /= 10, i--)
			ground[1][WIDTH + i] = (score_l % 10) + '0';

	for(i = 0 ; i < HEIGHT ; i++)
	{
		printf("%s", (char*)ground[i]);
	}
	usleep(delay);
}

void wall(struct snake_node head)
{
	int i;
	if(head.x == HEIGHT - 1 || head.y == WIDTH - 1 || head.x == 0 || head.y == 0 )
		game_over = 1;

	for(i = 0 ; i < snake_length - 1 ; i++)
	{
		if(head.x == snake[i].x && head.y == snake[i].y)
			game_over = 1;
	}
}

void snake_move()
{
	int i;
	struct snake_node head;
	head = snake[snake_length - 1];

	if(cur_dir == UP || cur_dir == DOWN)
		head.x += cur_dir;
	else
		head.y += (cur_dir-3);

 	wall(head);	
	if(game_over == 0)
	{
		if(head.x == food.x && head.y == food.y)
		{
			head = food;
			snake_length++;
			make_food();
			score += 10;
		}
		else
		{
			for(i = 0 ; i < snake_length - 1 ; i++)
				snake[i] = snake[i + 1];
		}
	
		head.dir = cur_dir;
		snake[snake_length - 1] = head;
	}
}

int keyboard()
{
	struct termios oldt, newt;
	int ch, oldf;

	tcgetattr(STDIN_FILENO, &oldt);
	newt = oldt;
	newt.c_lflag &= ~(ICANON | ECHO);
	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

	ch = getchar();

	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
	fcntl(STDIN_FILENO, F_SETFL, oldf);

	if(ch != EOF)
		return ch;
	else
		return 0;
}

void key_dir()
{
	char ch;
	if((ch = keyboard()) != 0)
		switch(ch)
		{
			case 'w':cur_dir = UP;break;
			case 'a':cur_dir = LEFT;break;
			case 's':cur_dir = DOWN;break;
			case 'd':cur_dir = RIGHT;break;
		}
}


void main()
{
	char ch;
	init();
	while(1)
	{
		speed();
		key_dir();
		snake_move();
		display();
		if(game_over == 1)break;
	}
	printf("\nScores:%d\n",score);
}
